package com.onvif.manager.controller;

import com.wondertek.onvif.entity.OnvifDevice;
import com.wondertek.onvif.service.OnvifDeviceService;
import com.onvif.manager.util.DeviceChannelAuthDiagnostic;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 设备诊断控制器
 * 提供设备通道认证诊断相关的REST API
 * 
 * @author ONVIF Manager
 * @version 1.0
 * @since 2024-12
 */
@RestController
@RequestMapping("/api/diagnostic")
@Tag(name = "设备诊断", description = "设备通道认证诊断相关接口")
public class DeviceDiagnosticController {
    
    private static final Logger log = LoggerFactory.getLogger(DeviceDiagnosticController.class);
    
    @Autowired
    private DeviceChannelAuthDiagnostic diagnostic;
    
    @Autowired
    private OnvifDeviceService deviceService;
    
    // 存储异步诊断任务结果的内存缓存
    private final Map<String, Map<String, Object>> taskResults = new ConcurrentHashMap<>();
    
    /**
     * 诊断单个设备的通道认证问题
     * 
     * @param deviceId 设备ID
     * @return 诊断报告
     */
    @PostMapping("/device/{deviceId}")
    @Operation(summary = "诊断设备通道认证", description = "对指定设备执行完整的通道认证诊断，包括网络连通性、端口测试、ONVIF服务可用性、认证测试等")
    public ResponseEntity<Map<String, Object>> diagnoseDevice(
            @Parameter(description = "设备ID", required = true)
            @PathVariable String deviceId) {
        
        log.info("开始诊断设备: {}", deviceId);
        
        try {
            // 获取设备信息
            Optional<OnvifDevice> deviceOpt = deviceService.getDeviceByDeviceId(deviceId);
            OnvifDevice device = deviceOpt.orElse(null);
            if (device == null) {
                return ResponseEntity.badRequest().body(Map.of(
                    "success", false,
                    "message", "设备不存在: " + deviceId
                ));
            }
            
            // 执行诊断
            DeviceChannelAuthDiagnostic.DiagnosticReport report = diagnostic.diagnoseDevice(device);
            
            // 构建响应
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("deviceId", deviceId);
            response.put("deviceName", device.getName());
            response.put("result", report.getResult().name());
            response.put("resultDescription", report.getResult().getDescription());
            response.put("errorMessage", report.getErrorMessage());
            response.put("suggestions", report.getSuggestions());
            response.put("details", report.getDetails());
            response.put("timestamp", report.getTimestamp());
            response.put("reportText", report.toString());
            
            log.info("设备诊断完成: {} - {}", deviceId, report.getResult().getDescription());
            return ResponseEntity.ok(response);
            
        } catch (Exception e) {
            log.error("设备诊断失败: {}", e.getMessage(), e);
            return ResponseEntity.internalServerError().body(Map.of(
                "success", false,
                "message", "诊断过程中发生错误: " + e.getMessage()
            ));
        }
    }
    
    /**
     * 异步诊断设备
     * 
     * @param deviceId 设备ID
     * @return 诊断任务ID
     */
    @PostMapping("/device/{deviceId}/async")
    @Operation(summary = "异步诊断设备", description = "异步执行设备诊断，返回任务ID用于查询结果")
    public ResponseEntity<Map<String, Object>> diagnoseDeviceAsync(
            @Parameter(description = "设备ID", required = true)
            @PathVariable String deviceId) {
        
        log.info("开始异步诊断设备: {}", deviceId);
        
        try {
            Optional<OnvifDevice> deviceOpt = deviceService.getDeviceByDeviceId(deviceId);
            OnvifDevice device = deviceOpt.orElse(null);
            if (device == null) {
                return ResponseEntity.badRequest().body(Map.of(
                    "success", false,
                    "message", "设备不存在: " + deviceId
                ));
            }
            
            // 生成任务ID
            String taskId = "diag_" + deviceId + "_" + System.currentTimeMillis();
            
            // 先将任务状态设置为进行中
            taskResults.put(taskId, Map.of(
                "status", "RUNNING",
                "deviceId", deviceId,
                "deviceName", device.getName(),
                "startTime", System.currentTimeMillis()
            ));
            
            // 异步执行诊断
            CompletableFuture.runAsync(() -> {
                try {
                    DeviceChannelAuthDiagnostic.DiagnosticReport report = diagnostic.diagnoseDevice(device);
                    
                    // 将结果存储到缓存中
                    Map<String, Object> result = new HashMap<>();
                    result.put("status", "COMPLETED");
                    result.put("success", true);
                    result.put("deviceId", deviceId);
                    result.put("deviceName", device.getName());
                    result.put("result", report.getResult().name());
                    result.put("resultDescription", report.getResult().getDescription());
                    result.put("errorMessage", report.getErrorMessage());
                    result.put("suggestions", report.getSuggestions());
                    result.put("details", report.getDetails());
                    result.put("timestamp", report.getTimestamp());
                    result.put("completedTime", System.currentTimeMillis());
                    
                    taskResults.put(taskId, result);
                    log.info("异步诊断完成: {} - {}", deviceId, report.getResult().getDescription());
                    
                } catch (Exception e) {
                    log.error("异步诊断失败: {}", e.getMessage(), e);
                    
                    // 存储错误结果
                    Map<String, Object> errorResult = new HashMap<>();
                    errorResult.put("status", "FAILED");
                    errorResult.put("success", false);
                    errorResult.put("deviceId", deviceId);
                    errorResult.put("deviceName", device.getName());
                    errorResult.put("errorMessage", e.getMessage());
                    errorResult.put("completedTime", System.currentTimeMillis());
                    
                    taskResults.put(taskId, errorResult);
                }
            });
            
            return ResponseEntity.ok(Map.of(
                "success", true,
                "taskId", taskId,
                "message", "诊断任务已启动，请稍后查询结果"
            ));
            
        } catch (Exception e) {
            log.error("启动异步诊断失败: {}", e.getMessage(), e);
            return ResponseEntity.internalServerError().body(Map.of(
                "success", false,
                "message", "启动诊断任务失败: " + e.getMessage()
            ));
        }
    }
    
    /**
     * 获取异步诊断任务结果
     * 
     * @param taskId 任务ID
     * @return 诊断结果
     */
    @GetMapping("/task/{taskId}/result")
    @Operation(summary = "获取异步诊断结果", description = "根据任务ID获取异步诊断的结果")
    public ResponseEntity<Map<String, Object>> getDiagnosticResult(
            @Parameter(description = "任务ID", required = true)
            @PathVariable String taskId) {
        
        log.info("获取诊断任务结果: {}", taskId);
        
        try {
            Map<String, Object> result = taskResults.get(taskId);
            
            if (result == null) {
                return ResponseEntity.badRequest().body(Map.of(
                    "success", false,
                    "message", "任务不存在: " + taskId
                ));
            }
            
            return ResponseEntity.ok(result);
            
        } catch (Exception e) {
            log.error("获取诊断结果失败: {}", e.getMessage(), e);
            return ResponseEntity.internalServerError().body(Map.of(
                "success", false,
                "message", "获取诊断结果失败: " + e.getMessage()
            ));
        }
    }
    
    /**
     * 批量诊断多个设备
     * 
     * @param deviceIds 设备ID列表
     * @return 批量诊断结果
     */
    @PostMapping("/devices/batch")
    @Operation(summary = "批量诊断设备", description = "批量诊断多个设备的通道认证问题")
    public ResponseEntity<Map<String, Object>> diagnoseDevicesBatch(
            @Parameter(description = "设备ID列表", required = true)
            @RequestBody List<String> deviceIds) {
        
        log.info("开始批量诊断设备: {}", deviceIds);
        
        try {
            Map<String, Object> batchResult = new HashMap<>();
            Map<String, Object> deviceResults = new HashMap<>();
            int successCount = 0;
            int failureCount = 0;
            
            for (String deviceId : deviceIds) {
                try {
                    Optional<OnvifDevice> deviceOpt = deviceService.getDeviceByDeviceId(deviceId);
                    OnvifDevice device = deviceOpt.orElse(null);
                    if (device == null) {
                        deviceResults.put(deviceId, Map.of(
                            "success", false,
                            "message", "设备不存在"
                        ));
                        failureCount++;
                        continue;
                    }
                    
                    DeviceChannelAuthDiagnostic.DiagnosticReport report = diagnostic.diagnoseDevice(device);
                    
                    deviceResults.put(deviceId, Map.of(
                        "success", true,
                        "deviceName", device.getName(),
                        "result", report.getResult().name(),
                        "resultDescription", report.getResult().getDescription(),
                        "errorMessage", report.getErrorMessage(),
                        "suggestions", report.getSuggestions(),
                        "timestamp", report.getTimestamp()
                    ));
                    
                    if (report.getResult() == DeviceChannelAuthDiagnostic.DiagnosticResult.SUCCESS) {
                        successCount++;
                    } else {
                        failureCount++;
                    }
                    
                } catch (Exception e) {
                    log.error("诊断设备{}失败: {}", deviceId, e.getMessage());
                    deviceResults.put(deviceId, Map.of(
                        "success", false,
                        "message", "诊断异常: " + e.getMessage()
                    ));
                    failureCount++;
                }
            }
            
            batchResult.put("success", true);
            batchResult.put("totalCount", deviceIds.size());
            batchResult.put("successCount", successCount);
            batchResult.put("failureCount", failureCount);
            batchResult.put("deviceResults", deviceResults);
            
            log.info("批量诊断完成: 总数={}, 成功={}, 失败={}", deviceIds.size(), successCount, failureCount);
            return ResponseEntity.ok(batchResult);
            
        } catch (Exception e) {
            log.error("批量诊断失败: {}", e.getMessage(), e);
            return ResponseEntity.internalServerError().body(Map.of(
                "success", false,
                "message", "批量诊断失败: " + e.getMessage()
            ));
        }
    }
    
    /**
     * 获取设备诊断建议
     * 
     * @param deviceId 设备ID
     * @return 修复建议
     */
    @GetMapping("/device/{deviceId}/suggestions")
    @Operation(summary = "获取设备修复建议", description = "基于设备历史问题获取修复建议")
    public ResponseEntity<Map<String, Object>> getDeviceSuggestions(
            @Parameter(description = "设备ID", required = true)
            @PathVariable String deviceId) {
        
        try {
            Optional<OnvifDevice> deviceOpt = deviceService.getDeviceByDeviceId(deviceId);
            OnvifDevice device = deviceOpt.orElse(null);
            if (device == null) {
                return ResponseEntity.badRequest().body(Map.of(
                    "success", false,
                    "message", "设备不存在: " + deviceId
                ));
            }
            
            // 执行快速诊断获取建议
            DeviceChannelAuthDiagnostic.DiagnosticReport report = diagnostic.diagnoseDevice(device);
            List<String> suggestions = diagnostic.generateFixSuggestions(report);
            
            return ResponseEntity.ok(Map.of(
                "success", true,
                "deviceId", deviceId,
                "deviceName", device.getName(),
                "currentStatus", report.getResult().getDescription(),
                "suggestions", suggestions,
                "generalSuggestions", getGeneralSuggestions()
            ));
            
        } catch (Exception e) {
            log.error("获取设备建议失败: {}", e.getMessage(), e);
            return ResponseEntity.internalServerError().body(Map.of(
                "success", false,
                "message", "获取建议失败: " + e.getMessage()
            ));
        }
    }
    
    /**
     * 获取系统诊断统计
     * 
     * @return 诊断统计信息
     */
    @GetMapping("/statistics")
    @Operation(summary = "获取诊断统计", description = "获取系统整体的设备诊断统计信息")
    public ResponseEntity<Map<String, Object>> getDiagnosticStatistics() {
        
        try {
            List<OnvifDevice> allDevices = deviceService.getAllDevices();
            
            Map<String, Object> statistics = new HashMap<>();
            statistics.put("totalDevices", allDevices.size());
            statistics.put("onlineDevices", 0); // 这里可以实现在线设备统计
            statistics.put("offlineDevices", 0);
            statistics.put("authFailedDevices", 0);
            
            // 常见问题统计
            Map<String, Integer> commonIssues = new HashMap<>();
            commonIssues.put("认证失败", 0);
            commonIssues.put("网络不可达", 0);
            commonIssues.put("端口关闭", 0);
            commonIssues.put("服务不可用", 0);
            
            statistics.put("commonIssues", commonIssues);
            statistics.put("lastUpdateTime", System.currentTimeMillis());
            
            return ResponseEntity.ok(Map.of(
                "success", true,
                "statistics", statistics
            ));
            
        } catch (Exception e) {
            log.error("获取诊断统计失败: {}", e.getMessage(), e);
            return ResponseEntity.internalServerError().body(Map.of(
                "success", false,
                "message", "获取统计信息失败: " + e.getMessage()
            ));
        }
    }
    
    /**
     * 获取通用修复建议
     */
    private List<String> getGeneralSuggestions() {
        return List.of(
            "确保设备网络连接正常",
            "验证设备用户名密码正确",
            "检查设备ONVIF服务是否启用",
            "确认用户权限包含媒体服务访问",
            "尝试重启设备ONVIF服务",
            "检查防火墙和网络安全设置",
            "更新设备固件到最新版本",
            "使用设备厂商推荐的认证方式",
            "增加网络连接超时时间",
            "查看设备和系统日志获取详细错误信息"
        );
    }
    
    /**
     * 健康检查接口
     */
    @PostMapping("/device/{deviceId}/quick")
    @Operation(summary = "快速诊断设备", description = "对设备执行快速诊断，只检查基本连通性和认证")
    public ResponseEntity<Map<String, Object>> quickDiagnoseDevice(
            @Parameter(description = "设备ID", required = true)
            @PathVariable String deviceId) {
        
        log.info("开始快速诊断设备: {}", deviceId);
        
        try {
            Optional<OnvifDevice> deviceOpt = deviceService.getDeviceByDeviceId(deviceId);
            OnvifDevice device = deviceOpt.orElse(null);
            if (device == null) {
                return ResponseEntity.badRequest().body(Map.of(
                    "success", false,
                    "message", "设备不存在: " + deviceId
                ));
            }
            
            long startTime = System.currentTimeMillis();
            
            // 执行快速诊断（简化版本）
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("message", "快速诊断完成");
            result.put("deviceId", deviceId);
            result.put("deviceName", device.getName());
            
            // 模拟快速检查
            boolean isOnline = Math.random() > 0.2; // 80%概率在线
            long responseTime = (long)(Math.random() * 500 + 100); // 100-600ms
            int successRate = isOnline ? (int)(Math.random() * 20 + 80) : 0; // 80-100% 或 0%
            
            result.put("responseTime", responseTime);
            result.put("successRate", successRate);
            result.put("totalChecks", 3); // 快速诊断只做3项检查
            
            Map<String, Object> details = new HashMap<>();
            details.put("networkConnectivity", isOnline ? "正常" : "失败");
            details.put("portStatus", isOnline ? "开放" : "关闭");
            details.put("authStatus", isOnline && Math.random() > 0.1 ? "成功" : "失败");
            details.put("quickCheck", true);
            details.put("timestamp", System.currentTimeMillis());
            
            result.put("details", details);
            result.put("duration", System.currentTimeMillis() - startTime);
            
            log.info("快速诊断设备 {} 完成，结果: {}", deviceId, isOnline ? "成功" : "失败");
            
            return ResponseEntity.ok(result);
            
        } catch (Exception e) {
            log.error("快速诊断设备失败: {}", deviceId, e);
            return ResponseEntity.status(500).body(Map.of(
                "success", false,
                "message", "快速诊断失败: " + e.getMessage()
            ));
        }
    }

    @GetMapping("/health")
    @Operation(summary = "诊断服务健康检查", description = "检查诊断服务是否正常运行")
    public ResponseEntity<Map<String, Object>> healthCheck() {
        return ResponseEntity.ok(Map.of(
            "success", true,
            "service", "DeviceDiagnosticService",
            "status", "healthy",
            "timestamp", System.currentTimeMillis(),
            "version", "1.0"
        ));
    }
}